package com.ruicar.afs.cloud.workflow.gwt.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.dynamicrequest.DynamicRequest;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.holder.TransRequestContextHolder;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.security.vo.UserVo;
import com.ruicar.afs.cloud.common.core.service.ServiceInfo;
import com.ruicar.afs.cloud.common.core.translog.service.GlobalTransService;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.data.lock.anno.Lock;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.*;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.AfsFLowRequestDto;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.WorkFlowResponse;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.*;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FLowNodeUserBean;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FlowCmdBean;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FlowInstanceBean;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FlowNodeBean;
import com.ruicar.afs.cloud.workflow.api.enums.AfsFlowRequestPath;
import com.ruicar.afs.cloud.workflow.config.WorkFlowConfig;
import com.ruicar.afs.cloud.workflow.gwt.service.WorkflowService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.text.MessageFormat;
import java.util.List;

@Service
@Slf4j
@AllArgsConstructor
public class WorkFlowServiceImpl implements WorkflowService {
    private final GlobalTransService globalTransService;
    private final DynamicRequest dynamicRequest;
    private final WorkFlowConfig workFlowConfig;

    private void processGlobalInfo() {
        if (TransRequestContextHolder.getClientInfo() == null || StringUtils.isEmpty(TransRequestContextHolder.getClientInfo().getAccessToken())) {
            TransRequestContextHolder.clear();
        }
    }

    private void checkResponse(IResponse<? extends WorkFlowResponse> iResponse, String message) {
        Assert.isTrue(CommonConstants.SUCCESS.equalsIgnoreCase(iResponse.getCode()) && (iResponse.getData() != null && iResponse.getData().getSuccess() == 1), (iResponse.getData() != null && StringUtils.isNotEmpty(iResponse.getData().getMessage())) ? iResponse.getData().getMessage() : (StringUtils.isNotEmpty(iResponse.getMsg()) ? iResponse.getMsg() : message));
    }

    @Override
    @Lock(keyConstant = ":lock-afs-start-flow", keys = "#startFlowRequest.bizDataId")
    public WorkFlowResponse startWorkFlow(StartFlowRequest startFlowRequest, JSONObject bizData) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(startFlowRequest.getAfsFlowKey()), "内部afsFlowKey 不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(startFlowRequest.getBizDataId()), "业务主键不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(startFlowRequest.getFlowName()), "流程名不能为空");
        AfsFLowRequestDto<StartFlowRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setBizData(bizData.toJSONString());
        afsFLowRequestDto.setFlowData(startFlowRequest);
        String globalKey = SecureUtil.md5(MessageFormat.format("START-FLOW-{0}-{1}-{2}", startFlowRequest.getAfsFlowKey(), startFlowRequest.getBizDataId(), ServiceInfo.getServiceName()));
        IResponse<WorkFlowResponse> iResponse = globalTransService.post(globalKey, workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.START_FLOW), afsFLowRequestDto, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "流程发起失败");
        return iResponse.getData();
    }

    @Override
    @Lock(keyConstant = ":lock-afs-flow-task-submit", keys = "#taskSubmitRequest.bizDataId")
    public WorkFlowResponse taskSubmit(TaskSubmitRequest taskSubmitRequest, JSONObject bizData) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(taskSubmitRequest.getAfsFlowKey()), "内部afsFlowKey 不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(taskSubmitRequest.getBizDataId()), "业务主键不能为空");
        AfsFLowRequestDto<TaskSubmitRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setBizData(bizData.toJSONString());
        afsFLowRequestDto.setFlowData(taskSubmitRequest);
        String globalKey = SecureUtil.md5(MessageFormat.format("SUBMIT-TASK-{0}-{1}-{2}", taskSubmitRequest.getAfsFlowKey(), taskSubmitRequest.getBizDataId(), taskSubmitRequest.getGwtUserId()));
        IResponse<WorkFlowResponse> iResponse = globalTransService.post(globalKey, workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.TASK_SUBMIT), afsFLowRequestDto, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "流程提交失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse taskReformist(TaskReformistRequest taskReformistRequest, JSONObject bizData) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(taskReformistRequest.getAfsFlowKey()), "内部afsFlowKey 不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(taskReformistRequest.getBizDataId()), "业务主键不能为空");
        AfsFLowRequestDto<TaskReformistRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setBizData(bizData.toJSONString());
        afsFLowRequestDto.setFlowData(taskReformistRequest);
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.TASK_REFORMIST), afsFLowRequestDto, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "流程转件失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse taskCallBack(TaskCallBackRequest taskCallBackRequest, JSONObject bizData) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(taskCallBackRequest.getAfsFlowKey()), "内部afsFlowKey 不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(taskCallBackRequest.getBizDataId()), "业务主键不能为空");
        AfsFLowRequestDto<TaskCallBackRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setBizData(bizData.toJSONString());
        afsFLowRequestDto.setFlowData(taskCallBackRequest);
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.TASK_CALL_BACK), afsFLowRequestDto, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "任务撤回失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse<FlowInstanceBean> queryFlowInstance(QueryFlowInstanceRequest queryFlowInstanceRequest) {
        processGlobalInfo();
        AfsFLowRequestDto<QueryFlowInstanceRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setFlowData(queryFlowInstanceRequest);
        IResponse<WorkFlowResponse<FlowInstanceBean>> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.QUERY_FLOW_INSTANCE), afsFLowRequestDto, new TypeReference<WorkFlowResponse<FlowInstanceBean>>() {
        });
        checkResponse(iResponse, "查询实例失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse<List<FlowCmdBean>> queryFlowCmd(QueryFLowCmdRequest queryFLowCmdRequest) {
        processGlobalInfo();
        AfsFLowRequestDto<QueryFLowCmdRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setFlowData(queryFLowCmdRequest);
        IResponse<WorkFlowResponse<List<FlowCmdBean>>> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.QUERY_CMD), afsFLowRequestDto, new TypeReference<WorkFlowResponse<List<FlowCmdBean>>>() {
        });
        checkResponse(iResponse, "查询命令失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse flowGiveUp(FLowGiveUpRequest fLowGiveUpRequest) {
        processGlobalInfo();
        AfsFLowRequestDto<FLowGiveUpRequest> afsFLowRequestDto = new AfsFLowRequestDto<>();
        afsFLowRequestDto.setFlowData(fLowGiveUpRequest);
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.FLOW_GIVE_UP), afsFLowRequestDto, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "终止流程失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse<List<FlowNodeBean>> queryAllNode() {
        processGlobalInfo();
        AfsFLowRequestDto afsFLowRequestDto = new AfsFLowRequestDto<>();
        IResponse<WorkFlowResponse<List<FlowNodeBean>>> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.QUERY_ALL_NODE), afsFLowRequestDto, new TypeReference<WorkFlowResponse<List<FlowNodeBean>>>() {
        });
        checkResponse(iResponse, "查询节点失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse<Page<FlowNodeBean>> pageQueryNode(Page page) {
        processGlobalInfo();
        IResponse<WorkFlowResponse<Page<FlowNodeBean>>> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.PAGE_QUERY_NODE), page, new TypeReference<WorkFlowResponse<Page<FlowNodeBean>>>() {
        });
        checkResponse(iResponse, "查询节点失败");
        return iResponse.getData();
    }


    @Override
    public WorkFlowResponse<Page<FLowNodeUserBean>> queryNodeUser(String nodeId, long pageIndex, long pageSize) {
        processGlobalInfo();
        QueryCondition<QueryNodeUserRequest> query = new QueryCondition<>();
        query.setPageNumber(pageIndex);
        query.setPageSize(pageSize);
        QueryNodeUserRequest request = new QueryNodeUserRequest();
        request.setNodeId(nodeId);
        query.setCondition(request);
        IResponse<WorkFlowResponse<Page<FLowNodeUserBean>>> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.PAGE_QUERY_NODE_USER), query, new TypeReference<WorkFlowResponse<Page<FLowNodeUserBean>>>() {
        });
        checkResponse(iResponse, "查询节点用户失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse addNodeUser(String nodeId, List<UserVo> userList) {
        processGlobalInfo();
        Assert.notEmpty(userList, "用户列表不能为空");
        Assert.noNullElements(userList, "用户列表不能有空数据");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.ADD_NODE_USER), AddNodeUserRequest.builder().nodeId(nodeId).userVoList(userList).build(), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "添加用户失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse changeTotalWeight(String userName, int totWeight) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(userName), "用户名不能为空");
        Assert.isTrue(totWeight > 0, "总权重不能小于0");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.CHANGE_TOTAL_WEIGHT), new ChangeTotalUserWeightRequest(userName, totWeight), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "总权重更改失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse changeWeight(List<String> gwtUserIds, int weight) {
        processGlobalInfo();
        Assert.notEmpty(gwtUserIds, "工作流引擎用户ID,不能为空");
        Assert.isTrue(weight > 0, "权重不能小于0");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.CHANGE_WEIGHT), new ChangeUserWeightRequest(gwtUserIds, weight), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "权重更改失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse clearTaskCount(List<String> gwtUserIds) {
        processGlobalInfo();
        Assert.notEmpty(gwtUserIds, "工作流引擎用户ID,不能为空");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.CLEAR_TASK_COUNT), gwtUserIds, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "清空待办失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse removeNodeUsers(List<String> gwtUserIds) {
        processGlobalInfo();
        Assert.notEmpty(gwtUserIds, "工作流引擎用户ID,不能为空");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.REMOVE_NODE_USER), gwtUserIds, new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "移除处理人失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse moveUserToNode(String gwtUserId, String oldNodeId, String newNodeId) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(gwtUserId), "工作流引擎用户ID,不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(oldNodeId), "老节点ID不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(newNodeId), "新节点ID不能为空");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.MOVE_USER_TO_NODE), new MoveUserToNewNodeRequest(gwtUserId, oldNodeId, newNodeId), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "转移处理人失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse resumeFlow(String dataId, String exceptionId) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(dataId), "业务ID,不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(exceptionId), "异常ID不能为空");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.RESUME_FLOW_INSTANCE), new ResumeFlowRequest(dataId,exceptionId), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "流程引擎异常处理失败");
        return iResponse.getData();
    }

    @Override
    public WorkFlowResponse pauseFlowInstance(String flowInstanceId) {
        processGlobalInfo();
        Assert.isTrue(StringUtils.isNotEmpty(flowInstanceId), "流程实例ID不能为空");
        IResponse<WorkFlowResponse> iResponse = dynamicRequest.post(workFlowConfig.getWorkFlowServer(), AfsEnumUtil.key(AfsFlowRequestPath.PAUSE_FLOW_INSTANCE), new PauseFlowInstance(flowInstanceId), new TypeReference<WorkFlowResponse>() {
        });
        checkResponse(iResponse, "暂停流程实例异常");
        return iResponse.getData();
    }
}
